/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Test object's hclass changing during concurrent mark.
 * If runtime sets a new hclass to an object GC barrier must be called.
 * Without barrier old hclass may be collected dispite it is reachable.
 */

function addProp(obj, prop) {
    obj[prop] = undefined;
}

function setProp(obj) {
    obj.prop = 1;
}

// Use wrapper to have ability to zero the referent
let holder = new Object();
// Create the object HClass we are interested in. New HClass is created.
holder.ref = new Object();
addProp(holder.ref, "prop");
// Poison addProp's IC
// Now the interesting HClass is in addProp's IC.
// Call addProp with different objects to make IC megamorphic.
addProp(new String(), "abc");
// Create IC for setProp
// The IC is created at the first call. We need to do it before concurrent mark to make sure
// the IC will not get into SATB.
setProp(new Object());
// Start GC with concurrent mark
let gc = startGC("threshold", function(marker) {
    let obj = holder.ref;
    // Mark setProp's IC before the interested HClass gets into.
    // So we sure the interested HClass is will not be marked from the IC.
    marker.markObjectRecursively(setProp);
    // Add obj.s HClass into setProp's IC.
    // The HClass is reachable from the IC but GC doesn't mark it because IC is already marked.
    setProp(obj);
    // Make transition to dictionary mode.
    // Object's hclass will be changed.
    obj[1025] = 0;
    // Forget the object.
    holder.ref = undefined;
    // At this moment the previous obj's HClass is reachable only from setProp's IC but is not marked.
    // Concurrent mark should delete the HClass and heap verifier should find a reference to a dead object
    // from setProp's IC.
});
